package com.qixiaobao.common.utils.pdf;


import com.itextpdf.kernel.colors.Color;
import com.itextpdf.kernel.colors.DeviceRgb;
import com.itextpdf.kernel.geom.Rectangle;
import com.itextpdf.kernel.pdf.*;
import com.itextpdf.kernel.pdf.canvas.PdfCanvas;
import com.itextpdf.kernel.pdf.canvas.parser.PdfCanvasProcessor;
import com.itextpdf.kernel.pdf.canvas.parser.listener.IPdfTextLocation;
import com.itextpdf.kernel.pdf.canvas.parser.listener.RegexBasedLocationExtractionStrategy;
import com.qixiaobao.common.core.domain.entity.InsureFileCoverRule;
import com.qixiaobao.common.core.domain.entity.OverArea;
import com.qixiaobao.common.core.domain.entity.PdfCoordinate;
import com.qixiaobao.common.core.domain.entity.PositionPDFTextStripper;
import com.qixiaobao.common.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.text.PDFTextStripper;
import org.apache.pdfbox.text.TextPosition;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.*;

/**
 * @ClassName PdfCoverUtils
 * @Author yangxm
 * @Description pdf内容遮盖工具类
 */
@Slf4j
public class PdfCoverUtils {


    //向上
    public static final String DIRECTION_UP = "1";
    //向下
    public static final String DIRECTION_DOWN = "2";
    //向左
    public static final String DIRECTION_LEFT = "3";
    //向右
    public static final String DIRECTION_RIGHT = "4";


    /**
     * @Description 获取关键字的坐标集合
     * @Author yangxm
     * @Date 2023/10/26 17:31
     * @Param [inputStream, keywordList]
     */
    public static Map<Integer, List<OverArea>> getKeywordPosition(String sourcePath, List<InsureFileCoverRule> keywordList){
        //key：pdf页码, value: 关键字坐标集合
        Map<Integer, List<OverArea>> map = new HashMap<>();
        PdfDocument pdfDocument = null;
        PdfReader pdfReader = null;
        try {
            //获取pdf文档
            pdfReader = new PdfReader(sourcePath);
            pdfDocument = new PdfDocument(pdfReader);
            //参数
            List<OverArea> overAreaList;
            PdfPage page = null;
            RegexBasedLocationExtractionStrategy regex;
            PdfCanvasProcessor canvasProcessor;
            Collection<IPdfTextLocation> resultantLocations;
            Rectangle rectangle;
            OverArea overArea;
            InsureFileCoverRule insureFileCoverRule;
            //循环pdf每页的数据
            for (int i = 1; i <= pdfDocument.getNumberOfPages(); i++) {
                overAreaList = new ArrayList<>();
                page = pdfDocument.getPage(i);
                for (int j = 0; j < keywordList.size(); j++) {
                    insureFileCoverRule = keywordList.get(j);
                    log.info("获取关键字的坐标集合，页码：{}, 保单遮盖规则：{}", i, insureFileCoverRule);
                    //若遮盖的规则中的页码包含0，所有页面的关键字都匹配
                    if (insureFileCoverRule.getPageNum().contains("0")){
                        regex = new RegexBasedLocationExtractionStrategy(insureFileCoverRule.getKeyword());
                        canvasProcessor = new PdfCanvasProcessor(regex);
                        canvasProcessor.processPageContent(page);
                        resultantLocations = regex.getResultantLocations();
                        //关键字可能在当前页面存在多个，将关键字所有坐标缓存到集合中
                        if (StringUtils.isNotEmpty(resultantLocations)){
                            for (IPdfTextLocation location : resultantLocations){
                                rectangle = location.getRectangle();
                                overArea = new OverArea();
                                overArea.setPageNum(i);
                                overArea.setX(rectangle.getX());
                                overArea.setY(rectangle.getY());
                                overArea.setWidth(rectangle.getWidth());
                                overArea.setHeight(rectangle.getHeight());
                                overArea.setKeyword(insureFileCoverRule.getKeyword());
                                //缓存到list
                                overAreaList.add(overArea);
                            }
                        }
                    }else if (insureFileCoverRule.getPageNum().contains(String.valueOf(i))){
                        regex = new RegexBasedLocationExtractionStrategy(insureFileCoverRule.getKeyword());
                        canvasProcessor = new PdfCanvasProcessor(regex);
                        canvasProcessor.processPageContent(page);
                        resultantLocations = regex.getResultantLocations();
                        //关键字可能在当前页面存在多个，将关键字所有坐标缓存到集合中
                        if (StringUtils.isNotEmpty(resultantLocations)){
                            for (IPdfTextLocation location : resultantLocations){
                                rectangle = location.getRectangle();
                                overArea = new OverArea();
                                overArea.setPageNum(i);
                                overArea.setX(rectangle.getX());
                                overArea.setY(rectangle.getY());
                                overArea.setWidth(rectangle.getWidth());
                                overArea.setHeight(rectangle.getHeight());
                                overArea.setKeyword(insureFileCoverRule.getKeyword());
                                //缓存到list
                                overAreaList.add(overArea);
                            }
                        }
                    }
                }
                //关键字的坐标不为空
                if (StringUtils.isNotEmpty(overAreaList)){
                    map.put(i, overAreaList);
                }
            }
        }catch (IOException e){
            log.error("获取关键字的坐标集合异常：{}", e);
            throw new RuntimeException("系统异常：" + e.getMessage());
        }finally {
            try {
                if (pdfReader != null){
                    pdfReader.close();
                }
                if (pdfDocument != null) {
                    pdfDocument.close();
                }
            }catch (IOException e){
                log.error("获取关键字的坐标集合异常：{}", e);
                throw new RuntimeException("系统异常：" + e.getMessage());
            }

        }
        return map;
    }
    /**
     * @Description pdf每页每行的第一个Y坐标集合
     * @Author yangxm
     * @Date 2023/10/26 16:39
     * @Param [inputStream]
     */
    public static Map<Integer, List<PdfCoordinate>> getFirstLineInfos(File file) {
        if (!file.exists()) {
            return null;
        }
        Map<Integer, List<PdfCoordinate>> lineInfos;
        PDDocument document = null;
        try {
            document = PDDocument.load(file);
            if(document.isEncrypted()) {
                throw new RuntimeException("文件加密了！");
            }else {
                PositionPDFTextStripper textStripper = new PositionPDFTextStripper();
                textStripper.setSortByPosition(true);
                textStripper.getText(document);
                lineInfos = textStripper.getFirstLineInfos();
                document.close();
            }
        } catch (IOException e) {
            log.error("获取pdf每页每行的第一个Y坐标集合异常：{}", e);
            throw new RuntimeException("系统异常：" + e.getMessage());
        }finally {
            try {
                if (document != null) {
                    document.close();
                }
            } catch (IOException e) {
                log.error("获取pdf每页每行的第一个Y坐标集合异常：{}", e);
                throw new RuntimeException("系统异常：" + e.getMessage());
            }
        }

        return lineInfos;
    }

    /**
     * 给PDF指定页位置纯色遮挡
     *
     * @param source  输入流
     * @param target  输出流
     * @param x       图片要打码区域左上角的横坐标
     * @param y       图片要打码区域左上角的纵坐标
     * @param pageNum 需要修改的页数
     * @param width   图片要打码区域的宽度
     * @param height  图片要打码区域的高度
     * @param color   遮挡颜色
     */
    public static void occlusion(InputStream source, OutputStream target, int pageNum,
                                 int x, int y, int width, int height, Color color) throws IOException {

        PdfDocument pdfDoc = null;
        try {
            WriterProperties wp = new WriterProperties();
            //禁止打印 复制 等操作
            wp.setStandardEncryption(null, null, 0, EncryptionConstants.DO_NOT_ENCRYPT_METADATA);

            pdfDoc = new PdfDocument(new PdfReader(source), new PdfWriter(target, wp));

            int numberOfPages = pdfDoc.getNumberOfPages();

            if (numberOfPages < pageNum || pageNum < 1) {
                log.error("指定修改页数{}大于PDF总页数{}", pageNum, numberOfPages);
                pdfDoc.close();
                return;
            }
            PdfCanvas canvas = new PdfCanvas(pdfDoc.getPage(pageNum));
            //初始阶段完成 开始替换
            canvas.saveState();
            //黑色背景覆盖
            canvas.setFillColor(color);
            //定位
            canvas.rectangle(x, y, width, height);
            //填充
            canvas.fill();
            //还原状态
            canvas.restoreState();
            pdfDoc.close();
        } finally {
            if (null != pdfDoc) {
                pdfDoc.close();
            }
        }
    }
    /**
     * @Description 根据关键字和遮盖规则，pdf部分遮盖
     * @Author yangxm
     * @Date 2023/10/26 17:35
     * @Param [inputStream, outputStream, list, firstLineInfoMap, ruleMap]
     */
    public static void pdfCover(String sourcePath, String targetPath, Map<Integer, List<OverArea>> overAreaListMap, Map<Integer, List<PdfCoordinate>> firstLineInfoMap, Map<String, InsureFileCoverRule> ruleMap){
        PdfDocument pdfDocument = null;
        PdfReader pdfReader = null;
        PdfWriter pdfWriter = null;
        List<OverArea> overAreaList;
        OverArea overArea;
        Integer pageNum;
        PdfPage page;
        PdfCanvas pdfCanvas;
        InsureFileCoverRule coverRule;
        //List<PdfCoordinate> yLines;
        //List<PdfCoordinate> sortList;
        //BigDecimal pageWidth;
        String keyword;
        float x;
        float y;
        float height;
        float width;
        /*float yCoordinate;
        float xCoordinate;
        float shelterWidth;*/
        try {
            //WriterProperties wp = new WriterProperties();
            //禁止打印 复制 等操作
            //wp.setStandardEncryption(null, null, EncryptionConstants.ALLOW_PRINTING, EncryptionConstants.DO_NOT_ENCRYPT_METADATA);
            pdfReader = new PdfReader(sourcePath);
            pdfWriter = new PdfWriter(targetPath);
            pdfDocument = new PdfDocument(pdfReader, pdfWriter);
            int numberOfPages = pdfDocument.getNumberOfPages();
            //关键字信息
            for (Map.Entry<Integer, List<OverArea>> entry : overAreaListMap.entrySet()){
                pageNum = entry.getKey();
                overAreaList = entry.getValue();
                if (numberOfPages < pageNum || pageNum < 1){
                    log.error("指定修改页数{}大于PDF总页数{}", pageNum, numberOfPages);
                    pdfDocument.close();
                    throw new RuntimeException("系统异常!");
                }
                //pdf页面
                page = pdfDocument.getPage(pageNum);
                //pdf页面宽度
                //pageWidth = new BigDecimal(Float.toString(page.getMediaBox().getWidth()));
                //pdf指定页面的每行的y坐标集合
                //yLines = firstLineInfoMap.get(pageNum);
                pdfCanvas = new PdfCanvas(page);
                pdfCanvas.saveState();
                for (int i = 0; i < overAreaList.size(); i++) {
                    //pdfCanvas.setFillColor(DeviceRgb.WHITE);
                    overArea = overAreaList.get(i);
                    //关键字
                    keyword = overArea.getKeyword();
                    //关键字的位置坐标
                    x = overArea.getX();
                    y = overArea.getY();
                    height = overArea.getHeight();
                    width = overArea.getWidth();
                    //遮盖规则
                    coverRule = ruleMap.get(keyword);
                    if (StringUtils.isNotBlank(coverRule.getColour())){
                        //遮盖颜色(RGB格式)
                        String[] colourRgb = coverRule.getColour().split(",");
                        if (colourRgb.length != 3){
                            throw new RuntimeException("遮盖颜色设置错误，请检查！");
                        }
                        //用背景色覆盖原来的文字，其实是文字与背景同色，但文字还在。
                        pdfCanvas.setFillColor(new DeviceRgb(Integer.parseInt(colourRgb[0]), Integer.parseInt(colourRgb[1]), Integer.parseInt(colourRgb[2])));
                    }else {
                        pdfCanvas.setFillColor(DeviceRgb.WHITE);
                    }
                    //向上遮盖
                    if (DIRECTION_UP.equals(coverRule.getCoverDirection())){
                        pdfCanvas.rectangle(x, y + Float.parseFloat(coverRule.getHeight().toString()), width +  Float.parseFloat(coverRule.getWidth().toString()), Float.parseFloat(coverRule.getHeight().toString()));
                        //向下遮盖
                    }else if (DIRECTION_DOWN.equals(coverRule.getCoverDirection())){
                        pdfCanvas.rectangle(x, y - Float.parseFloat(coverRule.getHeight().toString()), width +  Float.parseFloat(coverRule.getWidth().toString()), Float.parseFloat(coverRule.getHeight().toString()));
                        //向左遮盖
                    } else if (DIRECTION_LEFT.equals(coverRule.getCoverDirection())) {
                        pdfCanvas.rectangle(x - Float.parseFloat(coverRule.getWidth().toString()), y, Float.parseFloat(coverRule.getWidth().toString()), Float.parseFloat(coverRule.getHeight().toString()));
                        //向右遮盖
                    } else if (DIRECTION_RIGHT.equals(coverRule.getCoverDirection())) {
                        pdfCanvas.rectangle(x + Float.parseFloat(coverRule.getWidth().toString()), y, Float.parseFloat(coverRule.getWidth().toString()), Float.parseFloat(coverRule.getHeight().toString()));
                    }else {
                        throw new RuntimeException("保单遮盖方式错误");
                    }

                    /*//遮盖本行
                    if (coverRule.getMatchRule().contains("1")){
                        pdfCanvas.rectangle(x, overArea.getY(), pageWidth.subtract(new BigDecimal(Float.toString(x))).floatValue(), height);
                    }
                    //遮盖上一行(字体大小要和关键字一致)
                    if (coverRule.getMatchRule().contains("2")){
                        float finalY = y;
                        sortList = yLines.stream().filter(e -> e.getY().compareTo(finalY) > 0).collect(Collectors.toList());
                        //上一行X坐标
                        xCoordinate = sortList.get(sortList.size() -2).getX();
                        //上一行Y坐标
                        yCoordinate = sortList.get(sortList.size() -2).getY();
                        pdfCanvas.rectangle(xCoordinate, yCoordinate -1.5, pageWidth.subtract(new BigDecimal(Float.toString(xCoordinate))).floatValue(), height);
                    }
                    //遮盖下一行(字体大小要和关键字一致)
                    if (coverRule.getMatchRule().contains("3")){
                        float finalY = y;
                        sortList = yLines.stream().filter(e -> e.getY().compareTo(finalY) < 0).collect(Collectors.toList());
                        //下一行X坐标
                        xCoordinate = sortList.get(0).getX();
                        //下一行Y坐标
                        yCoordinate = sortList.get(0).getY();
                        pdfCanvas.rectangle(xCoordinate, yCoordinate -1.5, pageWidth.subtract(new BigDecimal(Float.toString(xCoordinate))).floatValue(), height);
                    }*/
                }
                pdfCanvas.fill();
                pdfCanvas.restoreState();
            }
        }catch (IOException e) {
            log.error("pdf内容遮盖异常：{}", e);
            throw new RuntimeException("系统异常：" + e.getMessage());
        }finally {
            try {
                if (pdfDocument != null) {
                    pdfDocument.close();
                }
                if (pdfReader != null){
                    pdfReader.close();
                }
                if (pdfWriter != null){
                    pdfWriter.close();;
                }
            } catch (IOException e) {
                log.error("保单遮盖异常：{}", e);
            }

        }
    }

    /**
     * 根据关键字获取文档指定内容（获取亚太的保险单号）
     * @param  file PDF文件对象
     * @param sourceTex 匹配的字符
     * @return 保单单号
     */
    public static String getValue(File file, String sourceTex) {
        final String[] value = new String[1];
        final boolean[] flag = {false};
        PDDocument document = null;
        PDFTextStripper textStripper;
        //获取文档坐标
        try {
            document = PDDocument.load(file);
            textStripper = new PDFTextStripper() {
                @Override
                protected void writeString(String text, List<TextPosition> textPositions) throws IOException {
                    if ("亚太财产保险有限公司".equals(text)){
                        flag[0] = true;
                    }
                    if (flag[0]){
                        if (text.contains(sourceTex)) {
                            String[] values = null;
                            if (text.contains(":")){
                                values = text.split(":");
                            } else if (text.contains("：")) {
                                values = text.split("：");
                            }
                            if (StringUtils.isNotEmpty(values)){
                                value[0] = values[1];
                            }
                        }
                    }
                }
            };
            textStripper.setSortByPosition(true);
            textStripper.setStartPage(1);
            textStripper.setEndPage(1);
            textStripper.getText(document);
            document.close();

        } catch (IOException e) {
            log.error("获取亚太保单的保险单号错误：{}", e);
        }finally {
            if (document != null){
                try {
                    document.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }
        return value[0];
    }

    public static void main(String[] args) {
        String path = "src/main/resources/file/06020400142112062023000004.pdf";
        System.out.println(getValue(new File(path), "保险单号"));
    }


}
